<template>
  <div class="app">
    <!-- 头部标题 -->
    <header class="app-header">
      <div class="header-content">
        <h1 class="app-title">DUT水库调度智能助手</h1>
        <div class="header-actions">
          <button class="btn-clear" @click="clearChatHistory" title="清空对话历史">
            清空历史
          </button>
        </div>
      </div>
    </header>

    <!-- 主体内容 -->
    <div class="app-body">
      <!-- 左侧边栏 - 对话历史 -->
      <aside class="sidebar">
        <div class="sidebar-header">
          <h3 class="sidebar-title">对话历史</h3>
        </div>
        <div class="sidebar-content">
          <div v-if="chatHistory.length === 0" class="empty-history">
            <p>暂无对话记录</p>
          </div>
          <div v-else class="history-list">
            <div 
              v-for="(item, index) in chatHistory" 
              :key="index"
              class="history-item"
              :class="{ active: currentConversationId === item.id }"
              @click="loadConversation(item)"
            >
              <div class="history-question">{{ item.question }}</div>
              <div class="history-answer-preview">{{ item.answerPreview }}</div>
              <div class="history-time">{{ formatTime(item.timestamp) }}</div>
            </div>
          </div>
        </div>
      </aside>

      <!-- 中间主体 - 对话区域 -->
      <main class="chat-container">
        <!-- 对话头部 -->
        <div class="chat-header">
          <div class="chat-title">
            <span>智能对话</span>
          </div>
          <div class="chat-status" :class="{ connected: isConnected }">
            <span class="status-dot"></span>
            {{ isConnected ? '已连接' : '未连接' }}
          </div>
        </div>

        <!-- 对话内容 -->
        <div class="chat-messages" ref="chatMessages">
          <div v-if="messages.length === 0" class="welcome-screen">
            <h2 class="welcome-title">DUT水库调度智能助手</h2>
            <p class="welcome-subtitle">请在下方输入您的问题，我将为您提供专业的解答</p>
            
            <!-- 示例问题 -->
            <div class="sample-questions">
              <p class="sample-title">试试这些问题：</p>
              <div class="sample-list">-
                <button 
                  v-for="question in sampleQuestions" 
                  :key="question"
                  class="sample-btn"
                  @click="sendSampleQuestion(question)"
                >
                  {{ question }}
                </button>
              </div>
            </div>
          </div>

          <div v-else class="messages-list">
            <div 
              v-for="(message, index) in messages" 
              :key="index"
              class="message-item"
              :class="message.role"
            >
              <!-- 用户消息 -->
              <div v-if="message.role === 'user'" class="user-message">
                <div class="message-bubble user-bubble">
                  <div class="message-content">{{ message.content }}</div>
                </div>
              </div>

              <!-- 助手消息 -->
              <div v-else class="assistant-message">
                <div class="message-bubble assistant-bubble">
                  <div class="message-header">
                    <span class="assistant-name">智能助手</span>
                  </div>
                  
                  <!-- 文本来源（显示章节路径，只在有文本来源且无表格图片时显示） -->
                  <div v-if="message.text_sources && message.text_sources.length > 0 && !hasTableImages(message)" class="text-sources">
                    <div class="source-header">
                      <span class="source-icon">📖</span>
                      <span class="source-title">参考章节</span>
                    </div>
                    <div class="source-list">
                      <div v-for="(source, idx) in message.text_sources" :key="idx" class="source-tag">
                        {{ source }}
                      </div>
                    </div>
                  </div>
                  
                  <!-- 最终答案内容（支持流式追加打字机效果） -->
                  <div class="message-content" v-html="formatMessage(message.content)"></div>

                  <!-- 自动展示的表格图片（在答案后面紧跟着展示） -->
                  <div v-if="message.table_images && Object.keys(message.table_images).length > 0" class="auto-table-images">
                    <div v-for="(images, tableName) in message.table_images" :key="tableName" class="auto-table-item">
                      <div class="auto-table-header">
                        <span class="auto-table-icon">📊</span>
                        <span class="auto-table-title">{{ tableName }}</span>
                      </div>
                      <div class="auto-table-gallery">
                        <div v-for="(imageUrl, idx) in images" :key="idx" class="auto-table-image-wrapper">
                          <img :src="imageUrl" :alt="`${tableName} - 图 ${idx + 1}`" class="auto-table-image" />
                        </div>
                      </div>
                    </div>
                  </div>

                  <!-- 匹配到的问题（答案下方，最多3个，用框框出来） -->
                  <!-- 如果展示了表格图片，就不显示相关问题 -->
                  <div v-if="message.matched_questions && message.matched_questions.length && !hasTableImages(message)" class="matched-questions">
                    <div class="mq-title">相关问题</div>
                    <div class="mq-list">
                      <div
                        v-for="(q, qIndex) in message.matched_questions"
                        :key="qIndex"
                        class="mq-card"
                        :class="{ 'mq-card-table': q.is_table }"
                        @click="handleQuestionClick(q)"
                      >
                        <span class="mq-text">{{ q.is_table ? (q.table_info ? q.table_info.table_title : q.question) : q.question }}</span>
                        <span v-if="q.is_table" class="mq-table-badge">展示</span>
                      </div>
                    </div>
                  </div>
                  
                  <!-- 表格图片查看器（支持多图片） -->
                  <div v-if="message.showingTableImage" class="table-image-viewer">
                    <div class="table-image-header">
                      <span class="table-image-title">{{ message.showingTableImage.table_title }}</span>
                      <button class="close-image-btn" @click="message.showingTableImage = null">×</button>
                </div>
                    
                    <!-- 多图片导航 -->
                    <div v-if="message.showingTableImage.images && message.showingTableImage.images.length > 1" class="image-nav">
                      <button 
                        v-for="(img, idx) in message.showingTableImage.images" 
                        :key="idx"
                        class="image-nav-btn"
                        :class="{ active: message.currentImageIndex === idx }"
                        @click="message.currentImageIndex = idx"
                      >
                        {{ img.description || `图 ${idx + 1}` }}
                      </button>
                    </div>
                    
                    <div class="table-image-body">
                      <img 
                        v-if="message.showingTableImage.images && message.showingTableImage.images[message.currentImageIndex || 0]"
                        :src="message.showingTableImage.images[message.currentImageIndex || 0].url" 
                        :alt="message.showingTableImage.table_title" 
                      />
                    </div>
                    
                    <div v-if="message.showingTableImage.table_description" class="table-image-description">
                      {{ message.showingTableImage.table_description }}
                    </div>
                  </div>
                </div>
              </div>
            </div>

            <!-- 正在输入指示器 -->
            <div v-if="isTyping" class="typing-indicator">
              <div class="typing-bubble">
                <div class="typing-dots">
                  <span></span>
                  <span></span>
                  <span></span>
                </div>
                <span class="typing-text">正在思考中...</span>
              </div>
            </div>
          </div>
        </div>

        <!-- 输入区域 -->
        <div class="chat-input-container">
          <div class="chat-input-wrapper">
            <textarea
              v-model="userInput"
              class="chat-input"
              placeholder="请输入您的问题..."
              @keydown.enter.prevent="sendMessage"
              :disabled="isLoading"
              rows="1"
            ></textarea>
            <button 
              class="send-btn" 
              @click="sendMessage"
              :disabled="!userInput.trim() || isLoading"
            >
              <span v-if="isLoading" class="loading-spinner"></span>
              <span v-else>发送</span>
            </button>
          </div>
        </div>
      </main>
    </div>
  </div>
</template>

<script>
import { ref, reactive, onMounted, nextTick, watch } from 'vue'
import { chatAPI } from './api/chat'

export default {
  name: 'App',
  setup() {
    // 状态管理
    const userInput = ref('')
    const messages = ref([])
    const isLoading = ref(false)
    const isTyping = ref(false)
    const isConnected = ref(true)
    const chatHistory = ref([])
    const currentConversationId = ref(null)
    const chatMessages = ref(null)

    // 示例问题
    const sampleQuestions = [
      '大伙房水库的调度规则是什么？',
      '大伙房自然地理位置图',
      '大伙房水库超标准洪水的调度方式是什么？'
    ]

    // 格式化消息内容
    const formatMessage = (content) => {
      console.log('📄 formatMessage 被调用，content长度:', content?.length, '内容:', content?.substring(0, 50))
      if (!content) return ''
      // 简单的换行处理
      return content.replace(/\n/g, '<br>')
    }

    // 格式化时间
    const formatTime = (timestamp) => {
      const date = new Date(timestamp)
      const now = new Date()
      const diff = now - date
      
      if (diff < 60000) return '刚刚'
      if (diff < 3600000) return `${Math.floor(diff / 60000)}分钟前`
      if (diff < 86400000) return `${Math.floor(diff / 3600000)}小时前`
      return date.toLocaleDateString('zh-CN')
    }

    // 滚动到底部
    const scrollToBottom = async () => {
      await nextTick()
      if (chatMessages.value) {
        chatMessages.value.scrollTop = chatMessages.value.scrollHeight
      }
    }

    // 打字机效果：全新实现，使用外部状态管理
    const TYPEWRITER_DELAY_MS = 40
    let typewriterState = {
      timer: null,
      buffer: '',
      currentIndex: -1,
      isDone: false,
      isRunning: false,
      question: ''
    }

    const startTypewriter = (msgIndex, question) => {
      console.log('🚀 启动打字机，消息索引:', msgIndex)
      
      // 如果已经在运行，先停止
      if (typewriterState.timer) {
        clearInterval(typewriterState.timer)
      }
      
      // 初始化状态
      typewriterState.currentIndex = msgIndex
      typewriterState.isRunning = true
      typewriterState.isDone = false
      typewriterState.question = question
      
      // 隐藏"思考中"提示
      isTyping.value = false
      
      // 启动定时器
      typewriterState.timer = setInterval(() => {
        try {
          const msg = messages.value[typewriterState.currentIndex]
          if (!msg) {
            console.error('❌ 找不到消息对象')
            stopTypewriter()
            return
          }
          
          // 检查缓冲区
          if (typewriterState.buffer && typewriterState.buffer.length > 0) {
            // 取出一个字符
            const char = typewriterState.buffer[0]
            typewriterState.buffer = typewriterState.buffer.slice(1)
            
            // 🔥 关键：直接通过索引更新，触发响应式
            messages.value[typewriterState.currentIndex].content += char
            
            console.log('✍️ 输出字符:', char, '当前长度:', messages.value[typewriterState.currentIndex].content.length, '剩余:', typewriterState.buffer.length)
            
            scrollToBottom()
          } else if (typewriterState.isDone) {
            // 缓冲区空且已完成
            console.log('✅ 打字机完成')
            stopTypewriter()
            
            // 设置匹配问题
            const finalMsg = messages.value[typewriterState.currentIndex]
            try {
              finalMsg.matched_questions = pickTopQuestions(finalMsg.qa_results || [])
              } catch (e) {
                console.error('❌ pickTopQuestions 错误:', e)
              finalMsg.matched_questions = []
              }
              
            // 更新历史记录
            updateChatHistory(typewriterState.question, finalMsg.content, finalMsg.qa_results)
            scrollToBottom()
          }
        } catch (error) {
          console.error('❌ 打字机错误:', error)
          stopTypewriter()
        }
      }, TYPEWRITER_DELAY_MS)
    }
    
    const stopTypewriter = () => {
      if (typewriterState.timer) {
        clearInterval(typewriterState.timer)
        typewriterState.timer = null
      }
      typewriterState.isRunning = false
          isLoading.value = false
          isTyping.value = false
      console.log('⏹️ 打字机已停止')
    }
    
    const addToTypewriterBuffer = (text) => {
      if (text) {
        typewriterState.buffer += text
        console.log('💾 添加到缓冲区:', text.length, '字符，总缓冲:', typewriterState.buffer.length)
        }
    }
    
    const markTypewriterDone = () => {
      typewriterState.isDone = true
      console.log('✅ 标记打字机完成')
    }

    // 选取匹配到的问题（从qa_results中提取，保留表格信息）
    // 如果有表格问题，返回所有表格问题；如果没有表格问题，返回最多3个普通问题
    const pickTopQuestions = (qaResults) => {
      console.log('🔍 pickTopQuestions 输入:', typeof qaResults, Array.isArray(qaResults), qaResults)
      
      // 确保 qaResults 是数组
      if (!qaResults || !Array.isArray(qaResults)) {
        console.warn('⚠️ qaResults 不是数组:', qaResults)
        return []
      }
      
      const seenQuestions = new Set()  // 用于去重普通问题
      const seenTableNames = new Set()  // 用于去重表格（按表格名）
      const tableQuestions = []
      const normalQuestions = []
      
      try {
        qaResults.forEach((qa, index) => {
          console.log(`  处理第${index}项:`, qa)
          const q = (qa?.question || '').trim()
          if (!q) return
          
          // 分类收集表格问题和普通问题
          if (qa.is_table) {
            // 表格问题按 table_name 去重
            const tableName = qa.table_info?.table_name || qa.table_info?.table_title
            if (tableName && !seenTableNames.has(tableName)) {
              seenTableNames.add(tableName)
              tableQuestions.push({
                question: q,
                is_table: true,
                table_info: qa.table_info || null
              })
            }
          } else {
            // 普通问题按问题文本去重
            if (!seenQuestions.has(q)) {
              seenQuestions.add(q)
              normalQuestions.push({
                question: q,
                is_table: false
              })
            }
          }
        })
      } catch (e) {
        console.error('❌ forEach 错误:', e)
      }
      
      // 如果有表格问题，返回所有表格问题
      // 如果没有表格问题，返回最多3个普通问题
      let result = []
      if (tableQuestions.length > 0) {
        result = tableQuestions  // 返回所有表格问题
      } else {
        result = normalQuestions.slice(0, 3)  // 取最多3个普通问题
      }
      
      console.log('✅ pickTopQuestions 返回:', result)
      return result
    }

    // 过滤掉表格问题，只返回普通QA
    const getNonTableQAResults = (qaResults) => {
      if (!qaResults || !Array.isArray(qaResults)) return []
      return qaResults.filter(qa => !qa.is_table)
    }

    // 判断消息是否包含表格图片
    const hasTableImages = (message) => {
      return message.table_images && 
             typeof message.table_images === 'object' && 
             Object.keys(message.table_images).length > 0
    }

    // 处理问题点击事件
    const handleQuestionClick = (q) => {
      if (!q) return
      
      // 如果是表格问题，找到对应的消息并显示图片
      if (q.is_table && q.table_info) {
        console.log('🖼️ 显示表格图片，table_info:', q.table_info)
        // 找到当前消息
        const msgIndex = messages.value.findIndex(msg => 
          msg.role === 'assistant' && 
          msg.matched_questions && 
          msg.matched_questions.some(mq => mq === q)
        )
        
        if (msgIndex >= 0) {
          // 使用Vue的响应式更新
          messages.value[msgIndex].showingTableImage = q.table_info
          messages.value[msgIndex].currentImageIndex = 0  // 初始化为第一张图片
        }
      } else {
        // 普通问题，发送查询
        const questionText = typeof q === 'string' ? q : q.question
        userInput.value = questionText
      sendMessage()
      }
    }
    
    // 点击相关提问，直接发起该问题（保留用于兼容）
    const askSuggestedQuestion = (q) => {
      handleQuestionClick(q)
    }

    // 发送消息（流式输出 + 参考资料在上）
    const sendMessage = async () => {
      const question = userInput.value.trim()
      if (!question || isLoading.value) return

      // 添加用户消息
      messages.value.push({
        role: 'user',
        content: question
      })

      // 清空输入框
      userInput.value = ''
      isLoading.value = true
      isTyping.value = true

      await scrollToBottom()

      try {
        // 先插入一个空的助手消息，用于流式填充
        const assistantMsg = {
          role: 'assistant',
          content: '',
          qa_results: [],
          matched_questions: [],
          table_images: {},  // 表格图片
          text_sources: []   // 文本来源
        }
        messages.value.push(assistantMsg)
        const assistantMsgIndex = messages.value.length - 1
        console.log('📝 创建助手消息，索引:', assistantMsgIndex)

        // 使用SSE流式获取答案，并优先推送参考资料
        const useES = typeof window !== 'undefined' && typeof window.EventSource !== 'undefined'
        const streamFn = useES ? chatAPI.sendQuestionStreamES : chatAPI.sendQuestionStream
        console.log('🔵 使用流式方法:', useES ? 'EventSource' : 'fetch stream')
        
        let hasStartedTypewriter = false
        
        await streamFn(question, {
          onRefs: (qaResults) => {
            console.log('📚 收到参考资料:', qaResults?.length || 0, '条')
            messages.value[assistantMsgIndex].qa_results = qaResults
            scrollToBottom()
          },
          onTableImages: (tableImages) => {
            console.log('🖼️ 收到表格图片:', tableImages)
            messages.value[assistantMsgIndex].table_images = tableImages
            scrollToBottom()
          },
          onTextSources: (textSources) => {
            console.log('📖 收到文本来源:', textSources)
            messages.value[assistantMsgIndex].text_sources = textSources
            scrollToBottom()
          },
          onDelta: async (delta) => {
            console.log('📝 收到delta:', delta?.length || 0, '字符', '内容:', delta?.substring(0, 20))
            
            // 添加到打字机缓冲区
            addToTypewriterBuffer(delta)
            
            // 如果还没启动打字机，现在启动
            if (!hasStartedTypewriter) {
              console.log('⌨️ 首次收到数据，启动打字机')
              hasStartedTypewriter = true
              startTypewriter(assistantMsgIndex, question)
            }
          },
          onDone: async () => {
            console.log('✅ 流式传输完成')
            markTypewriterDone()
            
            // 如果打字机还没启动（比如答案为空），也要启动一次
            if (!hasStartedTypewriter) {
              console.log('⌨️ 流式完成但未启动打字机，补充启动')
              hasStartedTypewriter = true
              startTypewriter(assistantMsgIndex, question)
            }
          },
          onError: async (errMsg) => {
            console.warn('❌ SSE流式失败，回退到非流式接口:', errMsg)
            // 停止打字机
            stopTypewriter()
            
            // 回退到非流式接口
            const resp = await chatAPI.sendQuestion(question)
            messages.value[assistantMsgIndex].content = resp.answer
            messages.value[assistantMsgIndex].qa_results = resp.qa_results || []
            messages.value[assistantMsgIndex].table_images = resp.table_images || {}
            messages.value[assistantMsgIndex].text_sources = resp.text_sources || []  // 添加文本来源
            messages.value[assistantMsgIndex].matched_questions = pickTopQuestions(resp.qa_results || [])
            isLoading.value = false
            isTyping.value = false
            updateChatHistory(question, resp.answer, resp.qa_results || [])
            await scrollToBottom()
          }
        })

      } catch (error) {
        console.error('发送消息失败:', error)
        stopTypewriter()
        messages.value.push({ role: 'assistant', content: '抱歉，处理您的问题时出现错误，请稍后重试。' })
        isLoading.value = false
        isTyping.value = false
      }
    }

    // 发送示例问题
    const sendSampleQuestion = (question) => {
      userInput.value = question
      sendMessage()
    }

    // 更新对话历史
    const updateChatHistory = (question, answer, qaResults) => {
      const conversationId = Date.now()
      const answerPreview = answer.length > 100 ? answer.substring(0, 100) + '...' : answer
      
      chatHistory.value.unshift({
        id: conversationId,
        question,
        answer,
        answerPreview,
        qa_results: qaResults || [],
        timestamp: new Date()
      })

      // 限制历史记录数量
      if (chatHistory.value.length > 50) {
        chatHistory.value = chatHistory.value.slice(0, 50)
      }

      currentConversationId.value = conversationId
    }

    // 加载对话
    const loadConversation = (conversation) => {
      currentConversationId.value = conversation.id
      messages.value = [
        {
          role: 'user',
          content: conversation.question
        },
        {
          role: 'assistant',
          content: conversation.answer,
          qa_results: conversation.qa_results || [],
          matched_questions: pickTopQuestions(conversation.qa_results || [])
        }
      ]
    }

    // 清空对话历史
    const clearChatHistory = () => {
      if (confirm('确定要清空所有对话历史吗？')) {
        chatHistory.value = []
        currentConversationId.value = null
      }
    }

    // 监听消息变化，自动滚动
    watch(messages, () => {
      scrollToBottom()
    }, { deep: true })

    // 组件挂载时初始化
    onMounted(() => {
      // 检查后端连接
      chatAPI.checkConnection().then(connected => {
        isConnected.value = connected
      }).catch(() => {
        isConnected.value = false
      })
    })

    return {
      userInput,
      messages,
      isLoading,
      isTyping,
      isConnected,
      chatHistory,
      currentConversationId,
      chatMessages,
      sampleQuestions,
      formatMessage,
      formatTime,
      sendMessage,
      sendSampleQuestion,
      loadConversation,
      clearChatHistory,
      askSuggestedQuestion,
      getNonTableQAResults,
      handleQuestionClick,
      hasTableImages
    }
  }
}
</script>

<style scoped>
/* 全局样式 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.app {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: #F5F7FA;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
}

/* 头部样式 */
.app-header {
  background: #FFFFFF;
  color: #263238;
  padding: 0 2rem;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
  z-index: 100;
}

.header-content {
  max-width: 1400px;
  margin: 0 auto;
  height: 64px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.app-title {
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  color: #1976D2;
}

.header-actions {
  display: flex;
  gap: 1rem;
}

.btn-clear {
  background: transparent;
  color: #546E7A;
  border: 1px solid #CFD8DC;
  padding: 0.5rem 1.2rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
  transition: all 0.2s ease;
  font-weight: 500;
}

.btn-clear:hover {
  background: #F5F7FA;
  border-color: #1976D2;
  color: #1976D2;
}

/* 主体内容 */
.app-body {
  flex: 1;
  display: flex;
  max-width: 1400px;
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
  padding: 1.5rem;
  gap: 1.5rem;
}

/* 侧边栏 */
.sidebar {
  width: 280px;
  background: #FFFFFF;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.sidebar-header {
  padding: 1.2rem 1.5rem;
  border-bottom: 1px solid #E0E0E0;
  background: #FAFBFC;
}

.sidebar-title {
  font-size: 1rem;
  font-weight: 600;
  color: #263238;
}

.sidebar-content {
  flex: 1;
  overflow-y: auto;
  padding: 0.5rem;
}

.empty-history {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #90A4AE;
  padding: 2rem;
}

.empty-history p {
  margin-top: 0.5rem;
  font-size: 0.9rem;
}

.history-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.history-item {
  padding: 1rem;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s ease;
  background: #FFFFFF;
  border: 1px solid transparent;
}

.history-item:hover {
  background: #F5F7FA;
  border-color: #E0E0E0;
}

.history-item.active {
  background: #E3F2FD;
  border-color: #1976D2;
}

.history-question {
  font-weight: 600;
  color: #263238;
  margin-bottom: 0.5rem;
  font-size: 0.9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.history-answer-preview {
  font-size: 0.8rem;
  color: #546E7A;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 0.3rem;
}

.history-time {
  font-size: 0.75rem;
  color: #90A4AE;
}

/* 对话容器 */
.chat-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #FFFFFF;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

.chat-header {
  padding: 1.2rem 1.5rem;
  border-bottom: 1px solid #E0E0E0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: #FAFBFC;
}

.chat-title {
  font-size: 1rem;
  font-weight: 600;
  color: #263238;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.chat-status {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: #90A4AE;
}

.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #BDBDBD;
  animation: pulse 2s ease-in-out infinite;
}

.chat-status.connected .status-dot {
  background: #4CAF50;
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

/* 消息区域 */
.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  background: #FAFBFC;
}

.chat-messages::-webkit-scrollbar {
  width: 6px;
}

.chat-messages::-webkit-scrollbar-track {
  background: transparent;
}

.chat-messages::-webkit-scrollbar-thumb {
  background: #CFD8DC;
  border-radius: 3px;
}

.chat-messages::-webkit-scrollbar-thumb:hover {
  background: #B0BEC5;
}

/* 欢迎屏幕 */
.welcome-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 2rem;
}

.welcome-title {
  font-size: 1.8rem;
  color: #263238;
  margin-bottom: 0.8rem;
  font-weight: 600;
}

.welcome-subtitle {
  font-size: 1rem;
  color: #546E7A;
  margin-bottom: 2rem;
}

.sample-questions {
  width: 100%;
  max-width: 600px;
}

.sample-title {
  font-size: 0.95rem;
  color: #546E7A;
  margin-bottom: 1rem;
  font-weight: 500;
}

.sample-list {
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}

.sample-btn {
  padding: 1rem 1.5rem;
  background: #FFFFFF;
  border: 1px solid #E0E0E0;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s ease;
  text-align: left;
  font-size: 1rem;
  color: #263238;
  font-weight: 500;
}

.sample-btn:hover {
  background: #E3F2FD;
  border-color: #1976D2;
  color: #1976D2;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* 消息列表 */
.messages-list {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.message-item {
  display: flex;
  width: 100%;
}

/* 用户消息 */
.user-message {
  display: flex;
  justify-content: flex-end;
  width: 100%;
}

.user-bubble {
  background: #2196F3;
  color: white;
  max-width: 70%;
  padding: 1rem 1.2rem;
  border-radius: 12px 12px 4px 12px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

/* 助手消息 */
.assistant-message {
  display: flex;
  justify-content: flex-start;
  width: 100%;
}

.assistant-bubble {
  background: #FFFFFF;
  border: 1px solid #E0E0E0;
  max-width: 85%;
  padding: 1.2rem;
  border-radius: 12px 12px 12px 4px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}

.message-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.8rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid #F0F0F0;
}

.assistant-name {
  font-weight: 600;
  font-size: 0.9rem;
  color: #1976D2;
}

.message-content {
  color: #263238;
  line-height: 1.7;
  font-size: 1.05rem;
  word-wrap: break-word;
}

/* 用户消息白色 */
.user-message .message-content {
  color: white;
}

/* 只给AI回答加粗 */
.assistant-message .message-content {
  font-weight: 600;
}

/* 文本来源 */
.text-sources {
  margin-bottom: 1rem;
  padding: 1rem;
  background: linear-gradient(135deg, #FFF3E0 0%, #ffffff 100%);
  border-left: 4px solid #FF9800;
  border-radius: 6px;
}

.source-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.8rem;
}

.source-icon {
  font-size: 1.2rem;
}

.source-title {
  font-weight: 600;
  font-size: 0.95rem;
  color: #E65100;
}

.source-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.source-tag {
  display: inline-block;
  padding: 0.4rem 0.8rem;
  background: white;
  border: 1px solid #FFB74D;
  border-radius: 12px;
  font-size: 0.9rem;
  color: #E65100;
  font-weight: 500;
  transition: all 0.2s ease;
}

.source-tag:hover {
  background: #FFF8E1;
  border-color: #FF9800;
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(255, 152, 0, 0.2);
}

/* 匹配问题 */
.matched-questions {
  margin-top: 1.2rem;
  padding-top: 1.2rem;
  border-top: 1px solid #F0F0F0;
}

.mq-title {
  font-size: 0.9rem;
  font-weight: 600;
  color: #546E7A;
  margin-bottom: 0.8rem;
}

.mq-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.mq-card {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.8rem 1rem;
  background: #FAFBFC;
  border: 1px solid #E0E0E0;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.mq-card:hover {
  background: #E3F2FD;
  border-color: #1976D2;
  transform: translateX(4px);
}

.mq-number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  background: #1976D2;
  color: white;
  border-radius: 50%;
  font-size: 0.8rem;
  font-weight: 600;
  flex-shrink: 0;
}

.mq-text {
  font-size: 1rem;
  color: #263238;
  flex: 1;
}

.mq-card-table {
  background: linear-gradient(135deg, #E3F2FD 0%, #ffffff 100%);
  border-color: #1976D2;
}

.mq-card-table:hover {
  background: linear-gradient(135deg, #BBDEFB 0%, #E3F2FD 100%);
}

.mq-table-badge {
  background: #1976D2;
  color: white;
  padding: 0.2rem 0.6rem;
  border-radius: 12px;
  font-size: 0.75rem;
  font-weight: 600;
}

/* 自动展示的表格图片 */
.auto-table-images {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid #E0E0E0;
}

.auto-table-item {
  margin-bottom: 1.5rem;
  border: 1px solid #E0E0E0;
  border-radius: 8px;
  overflow: hidden;
  background: #FAFBFC;
}

.auto-table-item:last-child {
  margin-bottom: 0;
}

.auto-table-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 1rem;
  background: linear-gradient(135deg, #E3F2FD 0%, #ffffff 100%);
  border-bottom: 1px solid #E0E0E0;
}

.auto-table-icon {
  font-size: 1.2rem;
}

.auto-table-title {
  font-weight: 600;
  font-size: 1rem;
  color: #1976D2;
}

.auto-table-gallery {
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  background: white;
}

.auto-table-image-wrapper {
  position: relative;
  text-align: center;
}

.auto-table-image {
  max-width: 100%;
  height: auto;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  cursor: zoom-in;
  transition: transform 0.2s ease;
}

.auto-table-image:hover {
  transform: scale(1.02);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* 表格图片查看器（点击表格问题后显示） */
.table-image-viewer {
  margin-top: 1.5rem;
  border: 1px solid #E0E0E0;
  border-radius: 8px;
  overflow: hidden;
  background: #FAFBFC;
}

.table-image-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  background: #F5F7FA;
  border-bottom: 1px solid #E0E0E0;
}

.table-image-title {
  font-weight: 600;
  font-size: 1rem;
  color: #1976D2;
}

/* 多图片导航 */
.image-nav {
  display: flex;
  gap: 0.5rem;
  padding: 0.8rem 1rem;
  background: #FAFBFC;
  border-bottom: 1px solid #E0E0E0;
  flex-wrap: wrap;
}

.image-nav-btn {
  padding: 0.4rem 1rem;
  background: white;
  border: 1px solid #CFD8DC;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.85rem;
  color: #546E7A;
  transition: all 0.2s ease;
  font-weight: 500;
}

.image-nav-btn:hover {
  border-color: #1976D2;
  color: #1976D2;
  background: #F5F7FA;
}

.image-nav-btn.active {
  background: #1976D2;
  border-color: #1976D2;
  color: white;
}

.close-image-btn {
  background: transparent;
  border: none;
  font-size: 1.5rem;
  color: #90A4AE;
  cursor: pointer;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  transition: all 0.2s ease;
}

.close-image-btn:hover {
  background: #E0E0E0;
  color: #263238;
}

.table-image-body {
  padding: 1rem;
  text-align: center;
  background: white;
}

.table-image-body img {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.table-image-description {
  padding: 1rem;
  font-size: 0.9rem;
  color: #546E7A;
  border-top: 1px solid #E0E0E0;
  background: #F5F7FA;
}

/* 打字指示器 */
.typing-indicator {
  display: flex;
  justify-content: flex-start;
}

.typing-bubble {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 1rem 1.2rem;
  background: #FFFFFF;
  border: 1px solid #E0E0E0;
  border-radius: 12px 12px 12px 4px;
}

.typing-dots {
  display: flex;
  gap: 0.3rem;
}

.typing-dots span {
  width: 8px;
  height: 8px;
  background: #90A4AE;
  border-radius: 50%;
  animation: typing 1.4s ease-in-out infinite;
}

.typing-dots span:nth-child(1) {
  animation-delay: 0s;
}

.typing-dots span:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-dots span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes typing {
  0%, 60%, 100% {
    transform: translateY(0);
    opacity: 0.7;
  }
  30% {
    transform: translateY(-10px);
    opacity: 1;
  }
}

.typing-text {
  font-size: 0.9rem;
  color: #546E7A;
}

/* 输入区域 */
.chat-input-container {
  padding: 1.2rem 1.5rem;
  border-top: 1px solid #E0E0E0;
  background: #FFFFFF;
}

.chat-input-wrapper {
  display: flex;
  gap: 0.8rem;
  align-items: flex-end;
}

.chat-input {
  flex: 1;
  padding: 0.9rem 1.2rem;
  border: 1px solid #CFD8DC;
  border-radius: 6px;
  font-size: 1rem;
  resize: none;
  outline: none;
  transition: all 0.2s ease;
  font-family: inherit;
  max-height: 120px;
  line-height: 1.5;
  background: #FAFBFC;
}

.chat-input:focus {
  border-color: #1976D2;
  box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.1);
  background: #FFFFFF;
}

.chat-input:disabled {
  background: #F5F5F5;
  cursor: not-allowed;
}

.send-btn {
  padding: 0.9rem 2rem;
  background: #1976D2;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 1rem;
  font-weight: 600;
  transition: all 0.2s ease;
  min-width: 80px;
  white-space: nowrap;
  writing-mode: horizontal-tb;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.send-btn:hover:not(:disabled) {
  background: #1565C0;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(25, 118, 210, 0.3);
}

.send-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.loading-spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-top-color: white;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* 响应式设计 */
@media (max-width: 1024px) {
  .sidebar {
    width: 240px;
  }
}

@media (max-width: 768px) {
  .app-body {
    padding: 0.8rem;
    gap: 0.8rem;
  }

  .sidebar {
    display: none;
  }

  .user-bubble,
  .assistant-bubble {
    max-width: 90%;
  }

  .app-title {
    font-size: 1.2rem;
  }
}
</style>